home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / NNTPSUBR.C < prev    next >
Text File  |  1993-10-14  |  22KB  |  1,049 lines

  1. /*
  2.  *
  3.  * NNTP Server/Client Subroutines - See RFC977
  4.  * Jeffrey R. Comstock. - NR0D - Bloomington, Minnesota USA
  5.  * Copyright 1990 Jeffrey R. Comstock, All Rights Reserved.
  6.  * Permission granted for non-commercial copying and use, provided
  7.  * this notice is retained.
  8.  *
  9.  * DB3FL 9107xx: heavily rewritten and bug fixing in file-handling
  10.  * DB3FL 920121: splitted into several files
  11.  *
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <time.h>
  17. #include <dos.h>
  18. #include <conio.h>
  19. #include <io.h>
  20. #include <dir.h>
  21. #include <ctype.h>
  22. #include <sys/stat.h>
  23.  
  24. #include "global.h"
  25. #include "nntp.h"
  26. #include "ftp.h"
  27. #include "files.h"
  28. #include "socket.h"
  29.  
  30. #define    DOSLEN    8        /* max. length of dir/file-names */
  31.  
  32. int Filecheck = 0;
  33. int16 Nntpquiet = 0;
  34.  
  35.  
  36. /* main directory-creating routine
  37.  * returncode: -1 error; 0 success
  38.  */
  39. static int near
  40. make_dir(char *path)
  41. {
  42.     if(path == NULLCHAR)
  43.         return -1;
  44.  
  45.     if(access(path,0)) {
  46.         if(mkdir(path)) {
  47.             tprintf("Can't create %s: %s\n",path,sys_errlist[errno]);
  48.             return -1;
  49.         }
  50.     }
  51.     return 0;
  52. }
  53.  
  54. /* main file-checking routine
  55.  * returncode: -1 if error; 0 success */
  56. static int near
  57. check_file(char *path)
  58. {
  59.     if(access(path,0)) {
  60. /*
  61.         return Fclose(Fopen(path,WRITE_TEXT,0,0));
  62. */
  63.         return close(creat(path,S_IWRITE));
  64.     }
  65.     return 0;
  66. }
  67.  
  68. /* checks the file-system used for NNTP
  69.  * returncode: -1 if error; 0 success - and "Filecheck" is set to 1 */
  70. int
  71. check_system(void)
  72. {
  73.     FILE *f;
  74.     char line[LineLen], *cp, *cp1;
  75.     int error = 0;
  76.  
  77.     if (Post.host == NULLCHAR) {
  78.         cp = strxdup(Hostname);
  79.         if((cp1 = strchr(cp,'.')) != NULLCHAR)
  80.             *cp1 = '\0';
  81.         Post.host = strxdup(cp);
  82.         xfree(cp);
  83.     }
  84.     if(Filecheck) {
  85.         return 0;
  86.     }
  87.     error  = make_dir(Forward);
  88.     error |= check_file(Pointer);
  89.     error |= check_file(History);
  90.     error |= check_file(Active);
  91.     error |= check_file(Poll);
  92.  
  93.     if(error) {
  94.         goto quit;
  95.     }
  96.     sprintf(line,"%s/fwd.seq",News);
  97.     if(access(line,0)) {
  98.         if((f = Fopen(line,"w+",0,1)) == NULLFILE) {
  99.             goto quit;
  100.         }
  101.         fputs("1\n",f);
  102.         Fclose(f);
  103.     }
  104.     sprintf(line,"%s/sequence.seq",Mailqdir);
  105.     if(access(line,0)) {
  106.         if((f = Fopen(line,"w+",0,1)) == NULLFILE) {
  107.             goto quit;
  108.         }
  109.         fputs("1\n",f);
  110.         Fclose(f);
  111.     }
  112.     Filecheck = 1;
  113.     return 0;
  114.  
  115. quit:
  116.     Filecheck = 0;
  117.     tputs("Error in NNTP file system\n");
  118.     return -1;
  119. }
  120.  
  121. /* creating path to a new newsgroup
  122.  * handling of "." and "\" in pathnames especially MSDos */
  123. /* returncode: -1 error; 0 success */
  124. #ifdef NNTPENH
  125. int
  126. #else
  127. static int near
  128. #endif
  129. make_path(char *group,int w)
  130. {
  131.     FILE *f;
  132.     char *cp, *cp1, pathname[LineLen];
  133.     int got_it = 0;
  134.  
  135.     if (group == NULLCHAR
  136.       || (f = Fopen(Pointer,APPEND_TEXT,0,1)) == NULLFILE)
  137.         return -1;
  138.  
  139.     cp = strxdup(group);
  140.  
  141.     for(;;) {
  142.         if((cp1 = strchr(cp,'.')) != NULLCHAR) {
  143.             *cp1 = '\0';
  144.         } else {
  145.             got_it = 1;
  146.         }
  147.         sprintf(pathname,"%s/%s",News,cp);
  148.  
  149.         if(make_dir(pathname)) {
  150.             xfree(cp);
  151.             Fclose(f);
  152.             return -1;
  153.         }
  154.         if(got_it) {
  155.             if(w) {
  156.                 fprintf(f,"%s %s\n",group,pathname);
  157.             }
  158.             xfree(cp);
  159.             Fclose(f);
  160.             return 0;
  161.         }
  162.         *cp1 = '/';
  163.     }
  164. }
  165.  
  166. static int near
  167. update_list(struct nntpserv *a)
  168. {
  169.     FILE *f, *t;
  170.     char *p, *p1, l2[LineLen];
  171.  
  172.     if((f = Fopen(Active,READ_TEXT,a->s,0)) == NULLFILE)
  173.         return -1;
  174.  
  175.     if ((t = Tmpfile(0,1)) == NULLFILE) {
  176.         Fclose(f);
  177.         return -1;
  178.     }
  179.     p1 = a->ap->group;
  180.     a->ap->number = 0;
  181.  
  182.     while(fgets(a->buf,LineLen,f) != NULL) {
  183.         a->ap->tmpu = strcspn(a->buf," ");
  184.         strncpy(l2,a->buf,a->ap->tmpu);
  185.         l2[a->ap->tmpu] = '\0';
  186.  
  187.         if(strncmp(p1,l2,DOSLEN) == 0) {
  188.             p = strchr(a->buf,' ') + 1;
  189.             a->ap->number = (unsigned)atoi(p);
  190.             (a->ap->number)++;
  191.             p = strchr(p,' ');
  192.             fprintf(t,"%s %5.5u%s",p1,a->ap->number,p);
  193.         } else {
  194.             fputs(a->buf,t);
  195.         }
  196.     }
  197.     Fclose(f);
  198.     rewind(t);
  199.  
  200.     if((f = Fopen(Active,WRITE_TEXT,a->s,0)) == NULLFILE) {
  201.         Fclose(t);
  202.         return -1;
  203.     }
  204.     while(fgets(a->buf,LineLen,t) != NULL) {
  205.         fputs(a->buf,f);
  206.     }
  207.     Fclose(t);
  208.  
  209. #ifdef NNTPENH
  210.     /* highest article in active file = 0 and update allowed ? */
  211.     if((a->ap->number == 0) && fullauto) {
  212. #else
  213.     /* highest article in active file = 0 ? */
  214.     if(a->ap->number == 0) {
  215. #endif
  216.         make_path(a->ap->group,1);
  217.         a->ap->number = 1;
  218.         fprintf(f,"%s 00001 00001 y\n",a->ap->group);
  219.     }
  220.     Fclose(f);
  221.     return (a->ap->number);
  222. }
  223.  
  224. /* checks for a minimum header
  225.  * returncode: 0 complete; 1 not complete */
  226. int
  227. garbled(FILE *f)
  228. {
  229. /*
  230.  * The minimum requirement for an incoming article is that it must have
  231.  * a newsgroups: line, a message-id: line, a date: line, a from: line,
  232.  * a subject: line and a blank line to delimit header from body.
  233.  *
  234.  */
  235.     char line[LineLen];
  236.     int ok = 0;
  237.  
  238.     rewind(f);
  239.  
  240.     while(fgets(line,LineLen,f) != NULL) {
  241.         if (strnicmp(line,Hdrs[NEWSGROUPS],12) == 0)
  242.             ok |= 1;
  243.         if (strnicmp(line,Hdrs[MSGID],12) == 0)
  244.             ok |= 2;
  245.         if (strnicmp(line,Hdrs[DATE],6) == 0)
  246.             ok |= 4;
  247.         if (strnicmp(line,Hdrs[FROM],6) == 0)
  248.             ok |= 8;
  249.         if (strnicmp(line,Hdrs[SUBJECT],9) == 0)
  250.             ok |= 16;
  251.         if (check_blank(line))
  252.             break;
  253.     }
  254.     rewind(f);
  255.     return (ok == 31) ? 0 : 1;
  256. }
  257.  
  258. /* checkes if path to given article exists
  259.  * returncode: -1 error; 1 success; 0 no path */
  260. int
  261. get_path2(struct article *art)
  262. {
  263.     FILE *f;
  264.     char line[LineLen], *p = art->group;
  265.  
  266.     if(art->group == NULLCHAR
  267.       || (f = Fopen(Pointer,READ_TEXT,0,1)) == NULLFILE) {
  268.         return -1;
  269.     }
  270.     while(fgets(line,LineLen,f) != NULL) {
  271.         if(strcspn(line," ") != strlen(p)) {
  272.             continue;
  273.         }
  274.         if(strnicmp(p,line,strlen(p)) == 0) {
  275.             p = (strchr(line,' ')) + 1;
  276.             rip(p);
  277.             if(art->path != NULLCHAR) {
  278.                 xfree(art->path);
  279.             }
  280.             art->path = strxdup(p);
  281.             Fclose(f);
  282.             return 1;
  283.         }
  284.     }
  285.     Fclose(f);
  286.     return 0;
  287. }
  288.  
  289. /* returncode: -1 error; 0 success */
  290. static void near
  291. dup_f(FILE *in,FILE *out,struct nntpserv *mp)
  292. /* Path: bug in col 1 of article body bug fixed by G4JEC 901019....*/
  293. {
  294.     char *p;
  295.     int blank_line_flag = 1;
  296.  
  297.     while(fgets(mp->buf,LineLen,in) != NULL) {
  298.         if(blank_line_flag) {
  299.             if(strnicmp(mp->buf,Hdrs[PATH],5) == 0) {
  300.                  p = strchr(mp->buf,' ') + 1;
  301.                  fprintf(out,"%s%s!%s",Hdrs[PATH],Post.host,p);
  302.                  blank_line_flag = 0;                    /* DG1ZX */
  303.                  continue;
  304.             }
  305.         }
  306.         /* oh oh - nntpserv is modifying articles....*/
  307.         if(strlen(mp->buf) == 1 && mp->buf[0] == '.') {
  308.             continue;
  309.         }
  310.         fputs(mp->buf,out);
  311.     }
  312. }
  313. /* copy article to \spool\news\junk and update history and fwd.seq file
  314.  * returncode: < 1 if error; 1 success */
  315. static int near
  316. dofwd(struct nntpserv *mp,FILE *f,FILE *history)
  317. {
  318.     FILE *fwd;
  319.  
  320.     sprintf(mp->buf,"%s/fwd.seq",News);
  321.     if ((fwd = Fopen(mp->buf,"r+",mp->s,0)) == NULLFILE) {
  322.         return -1;
  323.     }
  324.     fgets(mp->buf,LineLen,fwd);
  325.     mp->hold_i = atoi(mp->buf) + 1;
  326.     fprintf(history," JUNK/%u",mp->hold_i);
  327.     rewind(fwd);
  328.     fprintf(fwd,"%u",mp->hold_i);
  329.     Fclose(fwd);
  330.  
  331.     sprintf(mp->buf,"%s/%u",Forward,mp->hold_i);
  332.     if ((fwd = Fopen(mp->buf,WRITE_TEXT,mp->s,0)) == NULLFILE) {
  333.         return -2;
  334.     }
  335.     rewind(f);
  336.     dup_f(f,fwd,mp);
  337.     Fclose(fwd);
  338.     return 1;
  339. }
  340.  
  341. /* file-receiving routine
  342.  * returncode: -1 if error or 'recvline' faults; 0 success; 1 if blank line */
  343. int
  344. recv_file(FILE *fp,int s)
  345. {
  346.     char line[LineLen];
  347.     int check = 0;
  348.  
  349.     while(recvline(s,line,LineLen) != -1) {
  350.         rip(line);
  351.  
  352.         if(strcmp(line,".") == 0) {
  353.             return 0;
  354.         }
  355.         if(!check) {                    /* only enabled on first line! */
  356.             check = 1;
  357.             if (*line == '\0') {         /* check for blank line */
  358.                 return 1;
  359.             }
  360.         }
  361.         fprintf(fp,"%s\n",line);
  362.     }
  363.     return -1;
  364. }
  365.  
  366. /* checks incoming article-id against existing articles
  367.  * returncode: -1 if error; 1 if article exists; 0 no article found */
  368. int
  369. check_article(char *id)
  370. {
  371.     char line[LineLen], *p = strchr(id,'<');
  372.     FILE *f;
  373.  
  374.     if(id == NULLCHAR
  375.       || p == NULLCHAR
  376.       || (f = Fopen(History,READ_TEXT,0,1)) == NULLFILE) {
  377.         return -1;
  378.     }
  379.     while(fgets(line,LineLen,f) != NULL) {
  380.         if(strncmp(line,p,strlen(p)) == 0) {
  381.             Fclose(f);
  382.             return 1;
  383.         }
  384.         pwait(NULL);
  385.     }
  386.     Fclose(f);
  387.     return 0;
  388. }
  389.  
  390. int
  391. xfer_article2(FILE *f,struct nntpserv *mp)
  392. {
  393.     char line[LineLen], l[LineLen], *p, *p1, *group = NULLCHAR, *from = NULLCHAR, his[MAXPATH];
  394.     FILE *fptr, *history;
  395.     int alpha, x;
  396. #ifdef CONTROL
  397.     int control = 0;
  398. #endif
  399.     struct tm *stm;
  400.  
  401.     if(f == NULLFILE
  402.       || (history = Fopen(History,APPEND_TEXT,mp->s,0)) == NULLFILE) {
  403.         xfree(mp->id);
  404.         return -1;
  405.     }
  406.     mp->ap = mxallocw(sizeof(struct article));
  407.  
  408.     while(fgets(line,LineLen,f) != NULL) {
  409.         rip(line);
  410.         if(*line == '\0') {
  411.             break;
  412.         }
  413.         if (strnicmp(line,Hdrs[FROM],6) == 0) {
  414.             p = strchr(line,' ') + 1;
  415.             from = strxdup(p);
  416.             continue;
  417.         }
  418.         if (strnicmp(line,Hdrs[NEWSGROUPS],12) == 0) {
  419.             char *cp = l;
  420.  
  421.             p = strchr(line,' ') + 1;
  422.             alpha = 0;
  423.  
  424.             while(*p != '\0') {
  425.                 if(isalnum(*p) && alpha < DOSLEN) {
  426.                     *cp++ = *p;
  427.                     alpha++;
  428.                 }
  429.                 if(*p == '.'|| *p == ',') {
  430.                     *cp++ = *p;
  431.                     alpha = 0;
  432.                 }
  433.                 p++;
  434.             }
  435.             *cp = '\0';
  436.  
  437.             group = strxdup(l);
  438.             continue;
  439.         }
  440.     }
  441.     stm = gmtime(&currtime);
  442.  
  443.     sprintf(his,"%s %2.2d%2.2d%2.2d %2.2d%2.2d%2.2d",
  444.         mp->id,
  445.         stm->tm_year,stm->tm_mon+1,stm->tm_mday,
  446.         stm->tm_hour,stm->tm_min,stm->tm_sec);
  447.  
  448.     mp->hold_i = 0;
  449.     p = group;
  450.     x = 1;
  451.     while (x) {
  452.         if ((p1 = strchr(p,',')) != NULLCHAR) {
  453.             p1 = line;
  454.             while (*p != ',') {
  455.                 *(p1++) = *(p++);
  456.             }
  457.             *p1 = '\0';
  458.             p++;
  459.             mp->ap->group = strxdup(line);
  460.         } else {
  461.             mp->ap->group = strxdup(p);
  462.             x = 0;
  463.         }
  464.         update_list(mp);
  465.         if (mp->ap->number > 0) {
  466.             get_path2(mp->ap);
  467.             mp->hold_i = 1;
  468.             sprintf(line,"%s/%u",mp->ap->path,mp->ap->number);
  469.             rewind(f);
  470.             if((fptr = Fopen(line,WRITE_TEXT,mp->s,0)) == NULLFILE) {
  471.                 Fclose(history);
  472.                 xfree(mp->ap->group);
  473.                 goto quit;
  474.             }
  475.             dup_f(f,fptr,mp);
  476.             Fclose(fptr);
  477.             fprintf(history,"%s %s/%u\n",his,mp->ap->group,mp->ap->number);
  478. #ifdef CONTROL
  479.             if (strcmp(mp->ap->group,"control") == 0) {
  480.                 control = 1;
  481.             }
  482. #endif
  483.             if(mp->ap->path != NULLCHAR) {
  484.                 xfree(mp->ap->path);
  485.             }
  486.         }
  487.         xfree(mp->ap->group);
  488.     }
  489.     if(mp->hold_i == 0) {
  490.         if((x = dofwd(mp,f,history)) < 1) {
  491.             mp->hold_i = 0;
  492.         }
  493. #ifdef NNTPENH
  494.         /* newsgroup did not exist in active file, so forward it to junk */
  495.         xfree(group);
  496.         group = strxdup("JUNK");
  497. #endif
  498.     }
  499.     Fclose(history);
  500.  
  501.     switch(Nntpquiet) {
  502.     case 0:
  503.         putch(7);
  504.     case 1:
  505.         /* timestamp by dc3sn */
  506.         tprintf("NNTP: new news for %s from %s at %s\n",
  507.             group,from,timestr(currtime));
  508.         break;
  509.     case 3:
  510.         log(-1,IPPORT_NNTP,"NNTP new news from %s",from);
  511.         break;
  512.     }
  513. #ifdef CONTROL
  514.     if (control == 1)
  515.         docontrol(f,mp);
  516. #endif
  517. quit:
  518.     xfree(mp->id);
  519.     xfree(mp->ap);
  520.     if(from != NULLCHAR)
  521.         xfree(from);
  522.     if(group != NULLCHAR)
  523.         xfree(group);
  524.     return 0;
  525. }
  526.  
  527. /* checks for not valid chars in a line
  528.  * returncode: 0 if valid; 1 if invalid */
  529. int
  530. check_blank(char *bp)
  531. {
  532.     char *cp = bp;
  533.  
  534.     if(*cp > ' ') {
  535.         return 0;
  536.     } else while(*cp) {
  537.         if(*cp++ > ' ') {
  538.             return 0;
  539.         }
  540.     }
  541.     return 1;
  542. }
  543.  
  544. /* converts timestring to unix-compatible structure
  545.  * returncode: 0 (!!) if error; > 0 success */
  546. static int32
  547. make_nntime(struct date *d,struct time *t,char *str)
  548. {
  549.     char *cp, tmp[3];
  550.  
  551.     if(str == NULLCHAR) {
  552.         return 0;
  553.     }                    
  554.     tmp[2] = '\0';
  555.     cp = str;
  556.     strncpy(tmp,cp,2);
  557.  
  558.     if((d->da_year = atoi(tmp) + 1900) < 1980) {
  559.         d->da_year = 1980;
  560.     }
  561.     if(d->da_year > 2099) {
  562.         return 0;
  563.     }
  564.     cp += 2;
  565.     strncpy(tmp,cp,2);
  566.     d->da_mon = atoi(tmp);
  567.     
  568.     if(d->da_mon < 1 || d->da_mon > 12) {
  569.         return 0;
  570.     }
  571.     cp += 2;
  572.     strncpy(tmp,cp,2);
  573.     d->da_day = atoi(tmp);
  574.     
  575.     if(d->da_day < 1 || d->da_day > 32) {
  576.         return 0;
  577.     }
  578.     cp += 3;
  579.     strncpy(tmp,cp,2);
  580.     
  581.     if((t->ti_hour = atoi(tmp)) > 24) {
  582.         return 0;
  583.     }
  584.     cp += 2;
  585.     strncpy(tmp,cp,2);
  586.     
  587.     if((t->ti_min = atoi(tmp)) > 60) {
  588.         return 0;
  589.     }
  590.     cp += 2;
  591.     strncpy(tmp,cp,2);
  592.     
  593.     if((t->ti_sec = atoi(tmp)) > 60) {
  594.         return 0;
  595.     }
  596.     t->ti_hund = 0;
  597.     return (dostounix(d,t));
  598. }
  599.  
  600. /* checks if two spaces exists in given string
  601.  * returncode: -1 if error; 1 success */
  602. static int near
  603. check_one(char *str)
  604. {
  605.     char *cp;
  606.  
  607.     if(str == NULLCHAR || (cp = strchr(str,' ')) == NULLCHAR) {
  608.         return -1;
  609.     }
  610.     if(strchr(++cp,' ') == NULLCHAR) {
  611.         return -1;
  612.     }
  613.     return 1;
  614. }
  615.  
  616. static int
  617. restreql(char *w,char *s)
  618. {
  619.     while (*s && *w) {
  620.         switch (*w) {
  621.             case '*':
  622.                 for (w++; *s; s++) {
  623.                     if (restreql(w, s)) {
  624.                         return 1;
  625.                     }
  626.                 }
  627.                 break;
  628.             default:
  629.                 if (*w != *s) {
  630.                     return 0;
  631.                 }
  632.                 w++, s++;
  633.                 break;
  634.         }
  635.     }
  636.     if (*s) {
  637.         return 0;
  638.     }
  639.     while (*w) {
  640.         if (*w++ != '*') {
  641.             return 0;
  642.         }
  643.     }
  644.     return 1;
  645. }
  646.  
  647. static int near
  648. ngmatcha(int (*func)(char *,char *),int dflt,struct g_list *ngspec,struct g_list *matchlist)
  649. {
  650.     char *cp;
  651.     int match = dflt;
  652.     struct g_list *n, *m = matchlist;
  653.  
  654.     for(;;) {
  655.         if ((cp = strchr(m->str,'/')) != NULLCHAR)
  656.             *cp = '\0';
  657.         n = ngspec;
  658.         for (;;) {
  659.             if (n->str[0] == '!') {      /* Handle negation */
  660.                 if((*func)(n->str + 1,m->str)) {
  661.                     match = 0;
  662.                 }
  663.             } else {
  664.                 if((*func)(n->str, m->str)) {
  665.                     match = 1;
  666.                 }
  667.             }
  668.             if(n->next == NULLG)
  669.                 break;
  670.             else
  671.                 n = n->next;
  672.         }
  673.         if (m->next == NULLG)
  674.             break;
  675.         else
  676.             m = m->next;
  677.     }
  678.     return (match);
  679. }
  680.  
  681. /*
  682.         checks if article is newer than date/time specified in string
  683.         and if the groups in the given string matches with the
  684.         newsgroups in historyfile.
  685.         If new news exist, MID from all articles are copied in temporary file
  686.         returncode: -1 if error; 0 if no new news; 1 new news available
  687. */
  688.  
  689. int
  690. newnews(struct nntpserv *mp,FILE *f)
  691. {
  692.     char *cp = mp->buf, *cp1, line[LineLen], groups[LineLen];
  693.     struct g_list *ng, *hist, *ngp, *histp, *ptr;
  694.     FILE *f1;
  695.     int match, j, all = 1, i = 1, error = -1;
  696.  
  697.     if(check_one(mp->buf) == -1) {
  698.         return -1;
  699.     }
  700.     /* cut off newsgroups from time/date */
  701.     while (*(cp++) > 32) {
  702.         i++;
  703.     }
  704.     if (strlen(cp) < 13) {
  705.         return -1;
  706.     }
  707.     strncpy(groups,mp->buf,i-1);
  708.     groups[i-1] = '\0';
  709.  
  710.     if(strcmp(groups,"*") != 0) {
  711.         all = 0;
  712.     }
  713.     /* convert date/time string in unixtime format */
  714.     mp->datest = (struct date *)mxallocw(sizeof(struct date));
  715.     mp->timest = (struct time *)mxallocw(sizeof(struct time));
  716.  
  717.     if((mp->unixtime = make_nntime(mp->datest,mp->timest,cp)) < 1)
  718.         goto quit;
  719.  
  720.     /* build list of all newsgroups in the given string */
  721.     if(!all) {
  722.         ng = ngp = (struct g_list *)mxallocw(sizeof(struct g_list));
  723.         cp = groups;
  724.  
  725.         for (;;) {
  726.             if(strchr(cp,',') == NULLCHAR ) {
  727.                 ng->str = strxdup(cp);
  728.                 ng->next = NULLG;
  729.                 break;
  730.             }
  731.  
  732.             j = strcspn(cp,",");
  733.             ng->str = (char *)mxallocw(j+1);
  734.             strncpy(ng->str,cp,j);
  735.             ng->str[j] = '\0';
  736.             ng->next = (struct g_list *)mxallocw(sizeof(struct g_list));
  737.             ng = ng->next;
  738.  
  739.             if((cp1 = strchr(cp,',')) != NULLCHAR) {
  740.                 cp = cp1 + 1;
  741.             } else {
  742.                 break;
  743.             }
  744.         }
  745.     }
  746.  
  747.     /* now compare date/time and newsgroups with all entries in history file */
  748.     if ((f1 = Fopen(History,READ_TEXT,0,1)) == NULLFILE) {
  749.         goto quit1;
  750.     }
  751.     error = 0;
  752.  
  753.     for (;;) {
  754.         if(fgets(line,LineLen,f1) == NULL)
  755.             break;
  756.         rip(line);
  757.  
  758.         if((mp->ftime = make_nntime(mp->datest,mp->timest,strchr(line,' ') + 1)) == 0)
  759.             /* something wrong with this line so stop searching */
  760.             break;
  761.  
  762.         /* article is older than date/time in given string.
  763.            ==> read next line from history */
  764.         if((mp->ftime - mp->unixtime) < 0)
  765.             continue;
  766.  
  767.         /* if article is newer, then check if newsgroups in given string
  768.            and entry in history matches */
  769.         if (!all) {
  770.             for(i = 3, cp = line; i; --i) {
  771.                 cp = strchr(cp,' ') + 1;
  772.             }
  773.             histp = (struct g_list *)mxallocw(sizeof(struct g_list));
  774.             hist = histp;
  775.  
  776.             /* build list of all newsgroups from the article */
  777.             for (;;) {
  778.                 if (strchr(cp,' ') == NULLCHAR) {
  779.                     hist->str = strxdup(cp);
  780.                     hist->next = NULLG;
  781.                     break;
  782.                 }
  783.                 j = strcspn(cp," ");
  784.                 hist->str = (char *)mxallocw(j+1);
  785.                 strncpy(hist->str,cp,j);
  786.                 hist->str[j] = '\0';
  787.                 hist->next = (struct g_list *)mxallocw(sizeof(struct g_list));
  788.                 hist = hist->next;
  789.  
  790.                 if((cp1 = strchr(cp,' ')) != NULLCHAR) {
  791.                     cp = cp1 + 1;
  792.                 } else {
  793.                     break;
  794.                 }
  795.             }
  796.  
  797.             /* now check if both list matches */
  798.             match = ngmatcha(restreql,0,ngp,histp);
  799.  
  800.             /* free list of all newsgroups specified in the article */
  801.             ptr = histp;
  802.  
  803.             for (;;) {
  804.                 ptr = histp->next;
  805.                 xfree(histp->str);
  806.                 xfree(histp);
  807.                 histp = ptr;
  808.                 if (histp == NULLG)
  809.                     break;
  810.             }
  811.             /* if no matches exists then read new line from history */
  812.             if(!match) {
  813.                 continue;
  814.             }
  815.         }
  816.  
  817.         /* we found a new news, so copy message id to file
  818.            and read next line from history */
  819.         error = 1;
  820.         cp = line;
  821.         while ( *cp > 32 ) {
  822.             fputc(*(cp++),f);
  823.         }
  824.         fputc('\n',f);
  825.     }
  826.  
  827.     Fclose(f1);
  828.  
  829. quit1:
  830.     /* free list of all newsgroups specified in the given string */
  831.     if(!all) {
  832.         ptr = ngp;
  833.  
  834.         for (;;) {
  835.             ptr = ngp->next;
  836.             xfree(ngp->str);
  837.             xfree(ngp);
  838.             ngp = ptr;
  839.             if (ngp == NULLG) {
  840.                 break;
  841.             }
  842.         }
  843.     }
  844. quit:
  845.     rewind(f);
  846.     xfree(mp->datest);
  847.     xfree(mp->timest);
  848.     return error;
  849. }
  850.  
  851. /* get id-number of message
  852.  * returncode: -1 if error; 0 if no message; 1 success */
  853. int
  854. get_id(struct nntpserv *mp)
  855. {
  856.     FILE *f;
  857.     char tmp[LineLen];
  858.  
  859.     if ((f = open_message(mp)) == NULLFILE)
  860.         return 0;
  861.  
  862.     while(fgets(tmp,LineLen,f) != NULL) {
  863.         if(check_blank(tmp)) {
  864.             break;
  865.         }
  866.         if(strnicmp(tmp,Hdrs[MSGID],12) == 0) {
  867.             Fclose(f);
  868.             strcpy(mp->buf,strchr(tmp,' '));
  869.             rip(mp->buf);
  870.             return 1;
  871.         }
  872.     }
  873.     Fclose(f);
  874.     strcpy(mp->buf,"\0");
  875.     return 0;
  876. }
  877.  
  878. int
  879. art_ret(struct nntpserv *mp,int flag)
  880. {
  881.     if(get_id(mp) < 1) {
  882.         return -1;
  883.     }
  884.     if(flag) {
  885.         usprintf(mp->s,retrieve,mp->pointer,mp->buf,artmsg);
  886.     }
  887.     return 0;
  888. }
  889.  
  890. /* main message-opening routine
  891.  * returncode: NULLFILE if error; filepointer success */
  892. FILE *
  893. open_message(struct nntpserv *mp)
  894. {
  895.     FILE *f;
  896.     char line[LineLen];
  897.  
  898.     sprintf(line,"%s/%u",mp->path,mp->pointer);
  899.  
  900.     if((f = Fopen(line,READ_TEXT,0,0)) == NULLFILE) {
  901.         usputs(mp->s,noart);
  902.     }
  903.     return f;
  904. }
  905.  
  906. /* returncode: -1 error; 1 success; 0 no entry */
  907. int
  908. get_path(struct nntpserv *mp)
  909. {
  910.     FILE *f;
  911.     char line[LineLen], *cp1 = mp->buf;
  912.     int i;
  913.  
  914.     if(mp->buf == NULLCHAR
  915.       || (f = Fopen(Pointer,READ_TEXT,mp->s,0)) == NULLFILE) {
  916.         return -1;
  917.     }
  918.     if(*cp1 == ' ') {
  919.         cp1++;
  920.     }
  921.     i = strlen(cp1);
  922.  
  923.     while(fgets(line,LineLen,f) != NULL) {
  924.         if(strcspn(line," ") != i) {
  925.             continue;
  926.         }
  927.         if(strnicmp(cp1,line,i) == 0) {
  928.             char *cp = (strchr(line,' ')) + 1;
  929.             rip(cp);
  930.             if(mp->path != NULLCHAR) {
  931.                 xfree(mp->path);
  932.             }
  933.             mp->path = strxdup(cp);
  934.             Fclose(f);
  935.             return 1;
  936.         }
  937.     }
  938.     Fclose(f);
  939.     return 0;
  940. }
  941.  
  942. /* Sends article <message-id> to the client or check if path to
  943.  * host we are polling now exists.
  944.  * Return value: -1 on error, 1 article sent, 0 no article
  945.  * check = 1 : check only pathfield in article
  946.  * check = 0 : send article
  947.  */
  948. int
  949. doarticle(struct nntpserv *mp,int flag,char *hname)
  950. {
  951.     FILE *f;
  952.     int32 ok = 0;
  953. /*
  954.     char *holds, *p = strchr(mp->buf,' '), *p2, line[LineLen];
  955. */
  956.     char *holds, *p = mp->buf, *p2, line[LineLen];
  957.  
  958.     if(p == NULLCHAR || (f = Fopen(History,READ_TEXT,0,0)) == NULLFILE) {
  959.         usputs(mp->s,badsyntax);
  960.         return -1;
  961.     }
  962.     while(fgets(line,LineLen,f) != NULL) {
  963.         if(strstr(line,p) != NULLCHAR) {
  964.             Fclose(f);
  965.             p = (strchr(line,' ')) + 14;    /* point to the first newsgroup */
  966.             p2 = strchr(p,'/');             /* point to article number */
  967.             mp->hold_i = mp->pointer;       /* save current pointer */
  968.             holds = strxdup(mp->path);      /* save path of current article */
  969.             mp->pointer = atoi((p2 + 1));   /* get the article number */
  970.  
  971.             if (mp->path != NULLCHAR) {
  972.                 xfree(mp->path);
  973.                 mp->path = '\0';
  974.             }
  975.             *p2 = '\0';
  976.             rip(p);
  977.             strcpy(mp->buf,p);
  978.  
  979.             if(strncmp(p + 1,"JUNK",6) == 0) {
  980.                 strcpy(mp->buf,Forward);
  981.                 mp->path = strxdup(mp->buf);
  982.             } else {
  983.                 get_path(mp);
  984.             }
  985.             if(hname == NULLCHAR ) {
  986.                 /* send article */
  987.                 if((f = open_message(mp)) == NULLFILE) {
  988.                     xfree(mp->path);                /* file not found */
  989.                     mp->path = strxdup(holds);
  990.                     mp->pointer = mp->hold_i;
  991.                     xfree(holds);
  992.                     return -1;
  993.                 }
  994.                 if(art_ret(mp,flag) != -1) {
  995.                     ok = sendfile(f, mp->s, ASCII_TYPE,0);
  996.                     ok = (ok == -1) ? -1 : 1;
  997.                     usputs(mp->s,NEol);
  998.                 }
  999.             } else {
  1000.                 int getpath = 0;
  1001.  
  1002.                 /* check only pathfield in article */
  1003.                 sprintf(line,"%s/%u",mp->path,mp->pointer);
  1004.  
  1005.                 if((f = Fopen(line,READ_TEXT,0,0)) == NULLFILE) {
  1006.                     xfree(mp->path);                /* file not found */
  1007.                     mp->path = strxdup(holds);
  1008.                     mp->pointer = mp->hold_i;
  1009.                     xfree(holds);
  1010.                     return -1;
  1011.                 }
  1012.                 while(!getpath && (fgets(line,LINELEN,f) != NULL)) {
  1013.                     if (strnicmp(line,Hdrs[PATH],6) != 0) {
  1014.                         continue;
  1015.                     }
  1016.                     ok = 1;             /* default: send article */
  1017.                     getpath = 1;        /* reset condition for while-loop */
  1018.  
  1019.                     /* skip first entry, because its our own hostname */
  1020.                     p2 = strstr(line,"!") + 1;
  1021.  
  1022.                     for (;;) {
  1023.                         /* cut off first entry and compare it with the hostname */
  1024.                         if ((p = strstr(p2,"!")) == NULL) {
  1025.                             break;
  1026.                         }
  1027.                         *p = '\0';
  1028.                         if(strcmpi(hname,p2) == 0) {
  1029.                             ok = 0;         /* oops, I've got you. */
  1030.                             break;          /* don't forward article */
  1031.                         }
  1032.                         p2 = ++p;
  1033.                     }
  1034.                 }
  1035.             }
  1036.             Fclose(f);
  1037.             xfree(mp->path);
  1038.             mp->path = strxdup(holds);
  1039.             mp->pointer = mp->hold_i;
  1040.             xfree(holds);
  1041.             return ((int)ok);
  1042.         }
  1043.     }
  1044.     Fclose(f);
  1045.     usputs(mp->s,noart);
  1046.     return 0;
  1047. }
  1048.  
  1049.